package com.marketfarm.server.dao;

import java.io.Serializable;
import java.util.List;
import java.util.logging.Logger;

import javax.jdo.FetchPlan;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.marketfarm.shared.entity.LoadableEntity;
import com.marketfarm.shared.entity.Usuario;

public class DAO {

	private Logger log = Logger.getLogger(this.getClass().getName());
	
	public Object merge(Object obj) throws Exception{
		PersistenceManager pm = null;
		try {
			pm = PMF.get().getPersistenceManager();
			obj = pm.makePersistent(obj);
		} catch (Exception e) {
			e.printStackTrace(System.err);
			throw e;
		}
		finally{
			if(pm != null) pm.close();
		}
		
		return obj;
	}
	
	public Object merge(Object obj, PersistenceManager pm) throws Exception{
		try {
			obj = pm.makePersistent(obj);
		} catch (Exception e) {
			e.printStackTrace(System.err);
			throw e;
		}
		
		return obj;
	}
	
	public void delete(Object obj, PersistenceManager pm) throws Exception{
		try {
			pm.deletePersistent(obj);
		} catch (Exception e) {
			e.printStackTrace(System.err);
			throw e;
		}
	}
	
	public <T> T load(PersistenceManager pm, Class<T> clazz, String key){
		pm.getFetchPlan().setMaxFetchDepth(FetchPlan.FETCH_SIZE_GREEDY);
		
		return pm.getObjectById(clazz, key);
	}
	
	public Object load(PersistenceManager pm, Serializable entity){
		pm.getFetchPlan().setMaxFetchDepth(FetchPlan.FETCH_SIZE_GREEDY);
		
		return pm.getObjectById(pm.getObjectId(entity));
	}
	
	public <T> List<T> buscar(Class<T> clazz, String[] colunas, Object[] valores, String orderBy)  throws Exception{
		return buscar(clazz, colunas, valores, false, orderBy, null);
	}
	
	public <T> List<T> buscar(Class<T> clazz, String[] colunas, Object[] valores, String orderBy, Integer maximumItens)  throws Exception{
		return buscar(clazz, colunas, valores, false, orderBy, maximumItens);
	}
	
	public <T> List<T> buscar(Class<T> clazz, String[] colunas, Object[] valores)  throws Exception{
		return buscar(clazz, colunas, valores, false, null, null);
	}
	
	public <T> List<T> buscar(Class<T> clazz, String[] colunas, Object[] valores,
			boolean fetchAll, String orderBy, Integer maximumItens)  throws Exception
	{
		PersistenceManager pm = null;
		
		if(colunas != null && valores != null && colunas.length != valores.length)
			throw new IllegalArgumentException("Colunas e valores devem ter o mesmo tamanho");
		
		try {
			pm = PMF.get().getPersistenceManager();
			Query query = criarQueryGenerica(clazz, colunas, valores, pm);
			
			if(fetchAll) query.getFetchPlan().setFetchSize(FetchPlan.FETCH_SIZE_GREEDY);
			if(orderBy != null)	query.setOrdering(orderBy);
			if(maximumItens != null) query.setRange(0, maximumItens);
			
			List<T> lista;
			
			if(valores != null)	lista = (List<T>)query.executeWithArray(valores);
			else lista = (List<T>)query.execute();
			//pm.detachCopyAll(lista);
			lista.size(); //BUG no data-nucleus, se não fizer lista.size mais tarde da um erro
			
			return lista;
			
		} catch (Exception e) {
			e.printStackTrace(System.err);
			throw e;
		}
		finally{
			if(pm != null){
//				pm.getTransaction().commit();
				pm.close();
//				EMF.get().close();
			}
		}
	}
	
	public <T> T buscaUnicaOuNull(Class<T> clazz, String[] colunas, Object[] valores)  throws Exception{
		return buscaUnicaOuNull(clazz, colunas, valores, false);
	}
	
	public <T> T buscaUnicaOuNull(Class<T> clazz, String[] colunas, Object[] valores, boolean fetchAll)  throws Exception{
		List<T> lista = buscar(clazz, colunas, valores);
		if(lista.size() > 0) return lista.get(0);
		
		return null;
	}

	private <T> Query criarQueryGenerica(Class<T> clazz, String[] colunas, Object[] valores, PersistenceManager pm) {
		StringBuilder sbQuery = new StringBuilder();
		StringBuilder sbParameter = new StringBuilder();
		if(colunas != null){
			for (int i = 0; i < colunas.length; i++) {
				if(i>0){
					sbQuery.append(" &&");
					sbParameter.append(", ");
				}
				sbQuery.append(colunas[i]).append(" == e").append(i);
				sbParameter.append(valores[i].getClass().getName()).append(" e").append(i);
			}
		}
		Query query;
		
		if(sbQuery.length() > 0) query = pm.newQuery(clazz, sbQuery.toString());
		else query = pm.newQuery(clazz);
		
		if(colunas != null && colunas.length > 0)
			query.declareParameters(sbParameter.toString());

		return query;
	}
}
